package com.blockchainenergy.blockChain;

import com.alibaba.fastjson.JSON;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 存储操作链的类
 **/
public class KeyChain {
    // 存储区块链
    private List<KeyBlock> chain;

    //  决定了挖矿的困难程度
    private final static String difficulty = "0000";

    // 用于存储网络中其他节点的集合
    private Set<String> nodes;

    public Set<String> getNodes() {
        return nodes;
    }

    public KeyChain() {
        // 用于存储网络中其他节点的集合
        nodes = new HashSet<>();
        // 初始化区块链以及当前的交易信息列表
        chain = new ArrayList<>();

        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
        // 创建创世区块
        newBlock(100L, "0", df.format(new Date()));
    }

    public List<KeyBlock> getChain() {
        return chain;
    }

    /**
     * @return 得到区块链中的最后一个区块
     */
    public KeyBlock lastBlock() {
        return getChain().get(getChain().size() - 1);
    }

    public String getLastBlockHash() {
        return (String) hash(lastBlock());
    }

    /**
     * 新建区块必经方法
     */
    public KeyBlock newBlock(Long proof, String previous_hash, String key) {
//        if(proof==null) proof = proofOfWork(Long.parseLong(lastBlock().get("proof") + ""));
        KeyBlock keyBlock = new KeyBlock();
        // 设置区块类型
        int size = getChain().size();
        keyBlock.setIndex(size);
        keyBlock.setTimestamp(System.currentTimeMillis());
        keyBlock.setKey(key);
        keyBlock.setPrevious_hash(previous_hash);
        // 如果没有传递上一个区块的hash就计算出区块链中最后一个区块的hash
        getChain().add(keyBlock);

        return keyBlock;
    }

    /**
     * 生成区块的 SHA-256格式的 hash值
     */
    public static Object hash(KeyBlock keyBlock) {
        return new Encrypt().getSHA256(JSON.toJSONString(keyBlock));
    }

    /**
     * 简单的工作量证明:
     */
    public Long proofOfWork(Long last_proof) {
        Long proof = 0L;
        while (!validProof(last_proof, proof)) {
            proof += 1;
        }
        return proof;
    }

    /**
     * 验证证明: 是否hash(last_proof, proof)以4个0开头?
     */
    public boolean validProof(Long last_proof, Long proof) {
        String guess = last_proof + "" + proof;
        //使用SHA256
        String guess_hash = new Encrypt().getSHA256(guess);
        return guess_hash.startsWith(difficulty);
    }


    /**
     * 验证链是否有效
     **/
    public boolean validChain(List<KeyBlock> chain) {
        KeyBlock lastKeyBlock = chain.get(0);
        int currentIndex = 1;
        while (currentIndex < chain.size()) {
            KeyBlock keyBlock = chain.get(currentIndex);
            // 检查block的hash是否正确
            if (!keyBlock.getPrevious_hash().equals(hash(lastKeyBlock))) {
                return false;
            }
            lastKeyBlock = keyBlock;
            currentIndex++;
        }
        return true;
    }

    public void addBlock(String s) {
        newBlock(null, getLastBlockHash(), s);
    }
}

